package org.tri.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
import org.hibernate.annotations.NaturalId;

/**
 * La clase {@code AbstractAnimal} representa un animal con su resprectiva
 * caravana. Esta clase sirve de base para mantener registros de animales
 * disponibles y animales considerados "historicos".
 *
 * @author kiira
 * @version 1.0, Nov 23, 2011
 */
@MappedSuperclass
public abstract class AbstractAnimal implements Serializable {

    /** Identificador único del animal en el sistema. */
    private long idAnimal;
    /** Identificador único del animal real. */
    private String caravana;
    /** Indica si el animal esta vivo o no. */
    private boolean viva = true;

    /**
     * Constructor sin parámetros utilizado por hibernate.
     */
    protected AbstractAnimal() {
    }//end constructor

    /**
     * Inicializa el animal con su correspondiente caravana.
     *
     * @param caravana identificador único del animal.
     */
    public AbstractAnimal( String caravana ) {
        this.caravana = caravana;

    }//end constructor

    /**
     * Devuelve el identificador único del objeto.
     *
     * @return identificador del objeto.
     */
    @Id
    @GeneratedValue ( strategy = GenerationType.IDENTITY )
    @Column ( name = "id_animal", nullable = false )
    public long getIdAnimal() {
        return idAnimal;

    }//end método getIdAnimal

    /**
     * Setea el identificador único del objeto. Para uso exclusivo de hibernate.
     *
     * @param idAnimal identificador a setear.
     */
    protected void setIdAnimal( long idAnimal ) {
        this.idAnimal = idAnimal;

    }//end método setIdAnimal

    /**
     * Devuelve el identificador del animal.
     *
     * @return número de caravana del animal.
     */
    @NaturalId
    @Column ( name = "caravana", nullable = false )
    public String getCaravana() {
        return caravana;

    }//end método getCaravana

    /**
     * Setea el identificador del animal
     *
     * @param caravana caravana a setear.
     */
    public void setCaravana( String caravana ) {
        this.caravana = caravana;

    }//end método setCaravana
    
    /**
     * Indica si el animal esta vivo o no.
     * @return <li>true si el animal esta vivo. <li>false si el animal esta
     * muerto
     */
    @Column( name = "viva", nullable = false )
    public boolean isViva() {
        return this.viva;
        
    }//end método isViva
    
    /**
     * Sete si el animal esta vivo o no.
     * @param viva valor a setear.
     */
    public void setViva( boolean viva ) {
        this.viva = viva;
        
    }//end método setViva
    

    /**
     * Método para comprobar si una caravana corresponde a la siguiente caravana
     * a la de este animal.
     * @param caravana caravana con la cual comparara.
     * @return <li>true si la caravana es la subsiguiente. <li>false si la 
     * caravana no corresponde a la subsiguiente.
     */
    public boolean esSiguienteCaravana( String caravana ) {
        //creamos la siguiente caravana
        String inicio = getCaravana().substring( 0, 6 );
        int numero = Integer.parseInt( getCaravana().substring( 6 ) ) + 1;

        if ( numero == 1000 ) {
            numero = 0;
            inicio = String.format( "%s%c", inicio.substring( 0, 5 ), inicio.charAt( 5 ) + 1 );

        }//end if            

        String siguiente = String.format( "%s%03d", inicio, numero );
        
        //y la comparamos con la que pasaron por parámetro
        return caravana.equals( siguiente );

    }//end método esSiguienteCaravana
       
    /**
     * Devuelve el identificador único que representa a este animal, es decir su
     * caravana.
     *
     * @return caravana del animal.
     */
    @Override
    public String toString() {
        return caravana;

    }//end método toString

    /**
     * Indica si este animal es igual a otro objeto pasado por parámetros. Si el
     * otro objeto se trata de un {@code AbstractAnimal} como este, se los
     * considera iguales cuando sus caravanas son iguales.
     *
     * @param obj objeto con el cual comparar.
     * @return <li>true si los objetos son equivalentes. <li>flase si los
     * objetos no son equivalentes.
     */
    @Override
    public boolean equals( Object obj ) {
        if ( obj == null )
            return false;
        if ( getClass() != obj.getClass() )
            return false;
        final AbstractAnimal other = (AbstractAnimal)obj;
        if ( ( this.caravana == null ) ? ( other.caravana != null ) : !this.caravana.equals( other.caravana ) )
            return false;

        return true;

    }//end método equals

    /**
     * Devuelve la computación de un número a partir de la caravana del animal,
     * para que el mismo pueda ser insertado en un {@code Set} sin peligro de
     * que se produzcan inconsistencia en los datos.
     *
     * @return código hash del objeto.
     */
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 53 * hash + ( this.caravana != null ? this.caravana.hashCode() : 0 );
        return hash;

    }//end método hashCode

    /**
     * Devuelve la compra en la que este animal fué adquirido.
     *
     * @return {@code AbstractCompra} en la que el animal fué adquirido.
     */
    public abstract AbstractCompra obtenerCompraActual();

    /**
     * Devuelve la venta en la que este animal fué vendido.
     *
     * @return {@code AbstractVenta} en la que el animal fué vendido.
     */
    public abstract AbstractVenta obtenerVentaActual();

    /**
     * Devuelve un listado de caravanas que se generan a partir de una caravana
     * inicial. El listado se conforma de manera que pueda o no incluir la 
     * caravana inicial, dado por el parámetro "incluirInicial" y contiene una
     * cantidad de N caravanas, siendo N inidicado por el parámetro "cantidad".
     *
     * @param caravanaInicial primer caravana del conjunto a generar.
     * @param cantidad cantidad de caravanas que debe tener el listado.
     * @param incluirInicial indica si incluir o no la caravana inicial en la
     * lista.
     * @return lista de caravanas generadas.
     * @throws NumberFormatException si el formato de la caravana inicial no
     * respeta el formato estándar (5 números del cuig y un contador
     * alfanúmerico compuesta por una letra seguida de 3 números)
     */
    public static List<String> generarCaravanas( String caravanaInicial, 
                                                 int cantidad, 
                                                 boolean incluirInicial )
            throws NumberFormatException {
        ArrayList<String> caravanas = new ArrayList<String>( cantidad );

        //dividimos la caravana en su parte inicial y final
        String inicio = caravanaInicial.substring( 0, 6 );
        int numero = Integer.parseInt( caravanaInicial.substring( 6 ) ) + 
                     (incluirInicial ? 0 : 1);

        //generamos las caravanas
        for ( ; cantidad > 0; cantidad--, numero++ ) {
            if ( numero == 1000 ) {
                numero = 0;
                inicio = String.format( "%s%c", inicio.substring( 0, 5 ), inicio.charAt( 5 ) + 1 );

            }//end if            

            caravanas.add( String.format( "%s%03d", inicio, numero ) );

        }//end for

        return caravanas;

    }//end método generarCaravanas  
    
    /**
     * Devuelve un listado de caravanas que se generan a partir de una caravana
     * inicial. El listado se conforma de manera que NO incluye la caravana 
     * indicada como inicial (ya que se supone que es la última caravana 
     * utilizada por un establecimiento y por lo tanto NO se encuentra
     * disponible) y contiene una cantidad de N caravanas, siendo N inidicado 
     * por el parámetro "cantidad"
     *
     * @param caravanaInicial primer caravana del conjunto a generar.
     * @param cantidad cantidad de caravanas que debe tener el listado.

     * @return lista de caravanas generadas.
     * @throws NumberFormatException si el formato de la caravana inicial no
     * respeta el formato estándar (5 números del cuig y un contador
     * alfanúmerico compuesta por una letra seguida de 3 números)
     */
    public static List<String> generarCaravanas( String caravanaInicial, 
                                                 int cantidad ) {
        return generarCaravanas( caravanaInicial, cantidad, false );
        
    }//end método generarCaravanas

}//end clase AbstractAnimal

